#ifndef __DS18B20_C__
#define __DS18B20_C__


/**
 *  DS18B20 时序原理
 * 1. 复位与响应:
 *    主机拉低DQ 480μs后释放，DS18B20会在15~60μs后拉低总线以响应，持续60~240μs。
 *
 * 2. 写入时序:
 *    - 写0: 主机拉低DQ 60~120μs再释放。
 *    - 写1: 主机拉低DQ 1~15μs后释放，其余时间拉高。
 *
 * 3. 读取时序:
 *    主机拉低DQ 1~5μs后释放，延时约15μs再采样DQ电平。
 */

#include "ds18b20.h"

static void DS18B20_Delay(uint32_t us)
{
    DWT_Delay_us(us);
}

static void DS18B20_DQ_OUT(DS18B20_t *hds18b20) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = hds18b20->pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(hds18b20->port, &GPIO_InitStruct);
}

static void DS18B20_DQ_IN(DS18B20_t *hds18b20) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = hds18b20->pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(hds18b20->port, &GPIO_InitStruct);
}

static void DS18B20_WriteBit(DS18B20_t *hds18b20, uint8_t bit) {
    DS18B20_DQ_OUT(hds18b20);
    HAL_GPIO_WritePin(hds18b20->port, hds18b20->pin, GPIO_PIN_RESET);
    if (bit) {
        DS18B20_Delay(5);
        HAL_GPIO_WritePin(hds18b20->port, hds18b20->pin, GPIO_PIN_SET);
        DS18B20_Delay(60);
    } else {
        DS18B20_Delay(60);
        HAL_GPIO_WritePin(hds18b20->port, hds18b20->pin, GPIO_PIN_SET);
        DS18B20_Delay(5);
    }
}

static uint8_t DS18B20_ReadBit(DS18B20_t *hds18b20) {
    uint8_t bit;
    DS18B20_DQ_OUT(hds18b20);
    HAL_GPIO_WritePin(hds18b20->port, hds18b20->pin, GPIO_PIN_RESET);
    DS18B20_Delay(2);
    HAL_GPIO_WritePin(hds18b20->port, hds18b20->pin, GPIO_PIN_SET);
    DS18B20_DQ_IN(hds18b20);
    DS18B20_Delay(10);
    bit = HAL_GPIO_ReadPin(hds18b20->port, hds18b20->pin);
    DS18B20_Delay(50);
    return bit;
}


static void DS18B20_WriteByte(DS18B20_t *hds18b20, uint8_t byte) {
    for(int i = 0; i < 8; i++) {
        DS18B20_WriteBit(hds18b20, (byte & 0x01));
        byte >>= 1;
    }
}

static uint8_t DS18B20_ReadByte(DS18B20_t *hds18b20) {
    uint8_t byte = 0;
    for(int i = 0; i < 8; i++) {
        byte |= DS18B20_ReadBit(hds18b20) << i;
    }
    return byte;
}

static uint8_t DS18B20_Reset(DS18B20_t *hds18b20) {
    DS18B20_DQ_OUT(hds18b20);
    HAL_GPIO_WritePin(hds18b20->port, hds18b20->pin, GPIO_PIN_RESET);
    DS18B20_Delay(480);
    HAL_GPIO_WritePin(hds18b20->port, hds18b20->pin, GPIO_PIN_SET);
    DS18B20_Delay(15);
    DS18B20_DQ_IN(hds18b20);
    DS18B20_Delay(15);
    if(HAL_GPIO_ReadPin(hds18b20->port, hds18b20->pin) == GPIO_PIN_RESET) {
        return 1;
    } else {
        return 0;
    }   // 返回1 表示复位成功 返回0 表示复位失败s
}






void DS18B20_Init(DS18B20_t *hds18b20, GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{

    // 初始化DS18B20
    hds18b20->port = GPIOx;
    hds18b20->pin = GPIO_Pin;

}


float DS18B20_ReadTemp(DS18B20_t *hds18b20)
{
    uint8_t temp_l, temp_h;
    int16_t raw;
    float temp;

    if (!DS18B20_Reset(hds18b20)) return -127.0f;

    DS18B20_WriteByte(hds18b20, 0xCC);  // Skip ROM
    DS18B20_WriteByte(hds18b20, 0x44);  // Start conversion
    HAL_Delay(750);                     // 等待转换完成（12位分辨率）

    if (!DS18B20_Reset(hds18b20)) return -127.0f;

    DS18B20_WriteByte(hds18b20, 0xCC);  // Skip ROM
    DS18B20_WriteByte(hds18b20, 0xBE);  // Read scratchpad

    temp_l = DS18B20_ReadByte(hds18b20);
    temp_h = DS18B20_ReadByte(hds18b20);

    raw = (temp_h << 8) | temp_l;
    temp = (float)raw / 16.0f;          // DS18B20默认12位分辨率

    return temp;
}

/**
 * @brief  启动DS18B20温度转换（非阻塞）
 * @param  hds18b20 DS18B20句柄指针
 * @retval 1: 启动成功, 0: 启动失败
 */
uint8_t DS18B20_StartConversion(DS18B20_t *hds18b20)
{
    if (!DS18B20_Reset(hds18b20)) return 0;

    DS18B20_WriteByte(hds18b20, 0xCC);  // Skip ROM
    DS18B20_WriteByte(hds18b20, 0x44);  // Start conversion

    return 1;
}

/**
 * @brief  检查转换是否完成并读取温度（非阻塞）
 * @param  hds18b20 DS18B20句柄指针
 * @retval 温度值(摄氏度): 转换完成并读取成功
 *          -999.0f: 转换未完成
 *          -127.0f: 读取失败或设备未响应
 * @note   当返回-999.0f时，表示转换仍在进行中，需要继续调用此函数直到转换完成
 */
float DS18B20_ReadTempNonBlocking(DS18B20_t *hds18b20)
{
    uint8_t temp_l, temp_h;
    int16_t raw;
    float temp;

    // 检查转换是否完成
    // 需要复位并发送命令才能检查转换状态
    if (!DS18B20_Reset(hds18b20)) return -127.0f;

    DS18B20_WriteByte(hds18b20, 0xCC);  // Skip ROM
    
    // 读取一个bit来检查转换状态
    // DS18B20在转换过程中，读取bit会返回0；转换完成后，读取bit会返回1
    uint8_t conversion_done = DS18B20_ReadBit(hds18b20);
    if (!conversion_done) {
        return -999.0f;  // 转换未完成
    }

    // 转换完成，读取温度数据
    if (!DS18B20_Reset(hds18b20)) return -127.0f;

    DS18B20_WriteByte(hds18b20, 0xCC);  // Skip ROM
    DS18B20_WriteByte(hds18b20, 0xBE);  // Read scratchpad

    temp_l = DS18B20_ReadByte(hds18b20);
    temp_h = DS18B20_ReadByte(hds18b20);

    raw = (temp_h << 8) | temp_l;
    temp = (float)raw / 16.0f;          // DS18B20默认12位分辨率

    return temp;
}



#endif /* __DS18B20_C__ */